#include "Socket.h"
#include "Logger.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

Socket::~Socket()
{
  close(m_sockfd);   
}
void Socket::bindAddress(const InetAddress &localAddress)
{  
  int ret = ::bind(m_sockfd, (struct sockaddr*)localAddress.getSockAddr(), sizeof(sockaddr_in));
  if (ret != 0) {
    LOG_FATAL("bind error");
  }
}
void Socket::listen()
{
  if (0 != ::listen(m_sockfd, 1024)) {
    LOG_FATAL("listen error");
  }
}
int Socket::accept(InetAddress* peerAddress)
{
  sockaddr_in addr;
  socklen_t len;
  bzero(&addr, sizeof(addr));
  int connfd = ::accept(m_sockfd, (sockaddr*)&addr, &len);
  if (connfd >= 0) {
    peerAddress->setSockAddr(addr);
  }
  return connfd;
}
void Socket::shutdownWrite()
{
  if (::shutdown(m_sockfd, SHUT_WR) < 0) {
    LOG_ERROR("shutdown write error");
  }
}

void Socket::setTcpNoDelay(bool on)
{
  int optval = on ? 1 : 0;
  ::setsockopt(m_sockfd, IPPROTO_TCP, TCP_NODELAY,
               &optval, static_cast<socklen_t>(sizeof optval));
  // FIXME CHECK
}

void Socket::setReuseAddr(bool on)
{
  int optval = on ? 1 : 0;
  ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR,
               &optval, static_cast<socklen_t>(sizeof optval));
  // FIXME CHECK
}

void Socket::setReusePort(bool on)
{
#ifdef SO_REUSEPORT
  int optval = on ? 1 : 0;
  int ret = ::setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEPORT,
                         &optval, static_cast<socklen_t>(sizeof optval));
  if (ret < 0 && on) {
    LOG_ERROR("setsockopt failed");
  }
#else
  if (on)
  {
    LOG_ERROR << "SO_REUSEPORT is not supported.";
  }
#endif
}

void Socket::setKeepAlive(bool on)
{
  int optval = on ? 1 : 0;
  ::setsockopt(m_sockfd, SOL_SOCKET, SO_KEEPALIVE,
               &optval, static_cast<socklen_t>(sizeof optval));
  // FIXME CHECK
}
